/**
 *       \file  py_calc_model.cpp
 *      \brief  Python wrappers for calc_model, calc_model_data
 *     \author  Sergey Miryanov
 *       \date  02.12.2009
 *  \copyright  This source code is released under the terms of 
 *              the BSD License. See LICENSE for more details.
 * */
#include "stdafx.h"

#ifdef BSPY_EXPORTING_PLUGIN
#include "boost_array_adapter.h"
#include "calc_model.h"
#include "py_calc_model.h"
#include BS_FORCE_PLUGIN_IMPORT ()
#include "py_scal_wrapper.h"
#include "py_data_class.h"
#include BS_STOP_PLUGIN_IMPORT ()

// WTF??
#include "well_results_storage.h"
#include "fip_results_storage.h"

#include "export_python_wrapper.h"

using namespace boost::python;


namespace blue_sky
  {
  namespace python
    {

    

    PY_EXPORTER (calc_model_data_exporter, empty_exporter)
      .add_property ("cap_pressure",              detail::boost_array_adapter (&T::cap_pressure))
      .add_property ("s_deriv_cap_pressure",      detail::boost_array_adapter (&T::s_deriv_cap_pressure))
      .add_property ("relative_perm",             detail::boost_array_adapter (&T::relative_perm))
      .add_property ("s_deriv_relative_perm",     detail::boost_array_adapter (&T::s_deriv_relative_perm))
      .add_property ("p_deriv_gas_oil_ratio",     &T::p_deriv_gas_oil_ratio)
      .add_property ("invers_fvf",                detail::boost_array_adapter (&T::invers_fvf))
      .add_property ("p_deriv_invers_fvf",        detail::boost_array_adapter (&T::p_deriv_invers_fvf))
      .add_property ("gor_deriv_invers_fvf",      &T::gor_deriv_invers_fvf)
      .add_property ("invers_visc",               detail::boost_array_adapter (&T::invers_viscosity))
      .add_property ("p_deriv_invers_visc",       detail::boost_array_adapter (&T::p_deriv_invers_viscosity))
      .add_property ("gor_deriv_invers_visc",     &T::gor_deriv_invers_viscosity)
      .add_property ("invers_visc_fvf",           detail::boost_array_adapter (&T::invers_visc_fvf))
      .add_property ("p_deriv_invers_visc_fvf",   detail::boost_array_adapter (&T::p_deriv_invers_visc_fvf))
      .add_property ("gor_deriv_invers_visc_fvf", &T::gor_deriv_invers_visc_fvf)
      .add_property ("density",                   detail::boost_array_adapter (&T::density))
      .add_property ("p_deriv_density",           detail::boost_array_adapter (&T::p_deriv_density))
      .add_property ("gor_deriv_density",         &T::gor_deriv_density)
      .add_property ("porosity",                  &T::porosity)
      .add_property ("p_deriv_porosity",          &T::p_deriv_porosity)
      .add_property ("truns_mult",                &T::truns_mult)
      .add_property ("p_deriv_truns_mult",        &T::p_deriv_truns_mult)
      .add_property ("mobility",                  detail::boost_array_adapter (&T::mobility))
      .add_property ("p_deriv_mobility",          detail::boost_array_adapter (&T::p_deriv_mobility))
      .add_property ("s_deriv_mobility",          detail::boost_array_adapter (&T::s_deriv_mobility))
      .add_property ("prev_fluid_volume",         detail::boost_array_adapter (&T::prev_fluid_volume))
    PY_EXPORTER_END;

    template <typename T>
    void
    export_calc_model_data_vector (const char *name)
    {
      class_ <T> (name)
        .def (vector_indexing_suite <T> ())
        ;
    }

    template <typename T>
    typename T::value_type
    get_pvt_item (T *t, size_t index)
    {
      return t->operator[] (index);
    }

    template <typename T>
    struct pvt_array_iterator
    {
      pvt_array_iterator (T *t)
      : array_ (t)
      , iterator_ (t->begin ())
      , iterator_end_ (t->end ())
      {
      }

      typename T::value_type
      next ()
      {
#ifdef _DEBUG
        if (iterator_end_ != array_->end ())
          {
            bs_throw_exception ("PVT array iterator not more valid");
          }
#endif

        if (iterator_ == iterator_end_)
          {
            PyErr_SetString (PyExc_StopIteration, "No more data");
            boost::python::throw_error_already_set ();
          }

        return *(iterator_++);
      }

      T                     *array_;
      typename T::iterator  iterator_;
      typename T::iterator  iterator_end_;
    };

    template <typename T>
    pvt_array_iterator <T>
    get_pvt_iterator (T *t)
    {
      return pvt_array_iterator <T> (t);
    }

    template <typename T>
    void
    export_pvt_iterator (const char *name)
    {
      using namespace boost::python;

      class_ <pvt_array_iterator <T> > (name, init <T *> ())
        .def ("next",     &pvt_array_iterator <T>::next)
        .def ("__iter__", pass_through)
        ;
    }

    template <template <typename> class T>
    void
    export_pvt_array (const char *name)
    {
      typedef std::vector <smart_ptr <T <base_strategy_di> > > T_di;
      typedef std::vector <smart_ptr <T <base_strategy_fi> > > T_fi;
      typedef std::vector <smart_ptr <T <base_strategy_mixi> > > T_mixi;

      class_ <T_di> (std::string (std::string (name) + "_di").c_str ())
        .def ("__getitem__",  get_pvt_item <T_di>)
        .def ("__len__",      &T_di::size)
        .def ("__iter__",     get_pvt_iterator <T_di>)
        ;
      class_ <T_fi> (std::string (std::string (name) + "_fi").c_str ())
        .def ("__getitem__",  get_pvt_item <T_fi>)
        .def ("__len__",      &T_fi::size)
        .def ("__iter__",     get_pvt_iterator <T_fi>)
        ;
      class_ <T_mixi> (std::string (std::string (name) + "_mixi").c_str ())
        .def ("__getitem__",  get_pvt_item <T_mixi>)
        .def ("__len__",      &T_mixi::size)
        .def ("__iter__",     get_pvt_iterator <T_mixi>)
        ;

      export_pvt_iterator <T_di> ("pvt_array_iter_di");
      export_pvt_iterator <T_fi> ("pvt_array_iter_fi");
      export_pvt_iterator <T_mixi> ("pvt_array_iter_mixi");
    }

    void py_export_calc_model()
    {
      strategy_exporter::export_base_ext <calc_model_data, calc_model_data_exporter, class_type::concrete_class> ("calc_model_data");

      export_calc_model_data_vector <shared_vector <calc_model_data <base_strategy_di> > >   ("calc_model_data_vector_di");
      export_calc_model_data_vector <shared_vector <calc_model_data <base_strategy_fi> > >   ("calc_model_data_vector_fi");
      export_calc_model_data_vector <shared_vector <calc_model_data <base_strategy_mixi> > > ("calc_model_data_vector_mixi");

      export_pvt_array <pvt_dead_oil> ("pvt_dead_oil_array");
      export_pvt_array <pvt_water> ("pvt_water_array");
      export_pvt_array <pvt_gas> ("pvt_gas");

      strategy_exporter::export_base <calc_model, calc_model_exporter> ("calc_model");
    }

  } //ns python
} //ns bs
#endif